﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.ObjectModel;

using EQEmu.Database;

namespace EQEmu.ZonePoints
{
    public class ZonePointsChangedEventArgs : EventArgs
    {
        public ZonePointsChangedEventArgs(IEnumerable<zone_points> added,IEnumerable<zone_points> removed)
        {
            Added = added;
            Removed = removed;
        }

        public IEnumerable<zone_points> Added { get; private set; }
        public IEnumerable<zone_points> Removed { get; private set; }
    }

    public class ZonePoints
    {
        protected ObservableCollection<zone_points> _points = new ObservableCollection<zone_points>();
        private string _zoneShortName;
        private int _zoneVersion;
        private bool _hasModifications;

        public event EventHandler<ZonePointsChangedEventArgs> ZonePointsCollectionChanged;

        public ZonePoints(string zoneShortName, int zoneVersion = 0)
        {
            _zoneShortName = zoneShortName;
            _zoneVersion = zoneVersion;

            _points.CollectionChanged += _points_CollectionChanged;
        }

        public string ZoneShortName
        {
            get { return _zoneShortName; }
        }

        public int ZoneVersion
        {
            get { return _zoneVersion; }
        }

        public IEnumerable<zone_points> Points
        {
            get { return _points; }
        }

        void _points_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            var added = e.NewItems != null ? e.NewItems.Cast<zone_points>() : null;
            var removed = e.OldItems != null ? e.OldItems.Cast<zone_points>() : null;
            OnZonePointsChanged(added,removed);
        }

        protected void OnZonePointsChanged(IEnumerable<zone_points> added, IEnumerable<zone_points> removed)
        {
            var e = ZonePointsCollectionChanged;
            if (e != null)
            {
                e(this, new ZonePointsChangedEventArgs(added, removed));
            }
        }

        public virtual bool HasModifications
        {
            get
            {
                return _hasModifications;
            }
        }

        public virtual zone_points CreatePoint()
        {
            var zp = new zone_points();
            zp.zone = this._zoneShortName;
            zp.version = this._zoneVersion;

            return zp;
        }

        public virtual void AddPoint(zone_points zp)
        {
            _points.Add(zp);
            _hasModifications = true;
        }

        public virtual void RemovePoint(zone_points zp)
        {
            _points.Remove(zp);
            _hasModifications = true;
        }

        public zone_points FindClosestZonePoint(double x, double y, double z, double tolerance=5.0)
        {
            foreach (var p in _points)
            {
                var testpoint = new System.Windows.Media.Media3D.Point3D(x, y, z);
                var ploc = new System.Windows.Media.Media3D.Point3D(p.x, p.y, p.z);
                if (Common.Functions.Distance(testpoint, ploc) <= tolerance)
                {
                    return p;
                }
                ploc = new System.Windows.Media.Media3D.Point3D(p.target_x, p.target_y, p.target_z);
                if (Common.Functions.Distance(testpoint, ploc) <= tolerance)
                {
                    return p;
                }                
            }
            return null;
        }
    }
}
